package com.dji.sample.common.util.kmlModel;
/**
 * @author 10587
 * @date 2022/9/27
 */

import com.alibaba.fastjson2.JSONObject;
import com.dji.sample.annotation.ActionParam;
import com.dji.sample.annotation.IncreaseId;
import com.dji.sample.wayline.model.dto.UploadKmlDto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.dom4j.Element;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author yjt
 * @date 2022-09-27
 * @description:
 */
@Data
public class TravelRecordRequest {

    public static final String ACTION_TRIGGER_NAME = "ActionTrigger";
    //经度
    public String lng;
    //纬度
    public String lat;
    //高度
    public String height;
    //点位名称
    public String name;
    //排序下标 生成航线
    public Integer index;

    /**
     * 飞行器偏航角
     */
    @JsonProperty(value = "waypointHeadingParam")
    public WaypointHeadingParam waypointHeadingParam = new WaypointHeadingParam();

    /**
     * 航点类型
     */
    @JsonProperty(value = "waypointTurnParam")
    public WaypointTurnParam waypointTurnParam = new WaypointTurnParam();

    /**
     * 动作组
     */
    @JsonProperty(value = "actionGroup")
    public ActionGroup actionGroup;

    public TravelRecordRequest() {
    }

    public TravelRecordRequest(String lng, String lat, String alt) {
        this.lng = lng;
        this.lat = lat;
        this.height = alt;
    }

    @Data
    static class WaypointHeadingParam {

        /**
         * followWayline：沿航线方向。飞行器机头沿着航线方向飞至下一航点
         * manually：手动控制。飞行器在飞至下一航点的过程中，用户可以手动控制飞行器机头朝向
         * fixed：锁定当前偏航角。飞行器机头保持执行完航点动作后的飞行器偏航角飞至下一航点
         * smoothTransition：自定义。通过“wpml:waypointHeadingAngle”给定某航点的目标偏航角，并在航段飞行过程中均匀过渡至下一航点的目标偏航角。
         */
        @JsonProperty(value = "waypointHeadingMode")
        public String waypointHeadingMode = "followWayline";

        /**
         * 给定某航点的目标偏航角，并在航段飞行过程中均匀过渡至下一航点的目标偏航角。
         */
        @JsonProperty(value = "waypointHeadingAngle")
        public String waypointHeadingAngle = "0";

        /**
         * clockwise：顺时针旋转飞行器偏航角
         * counterClockwise：逆时针旋转飞行器偏航角
         * followBadArc：沿最短路径旋转飞行器偏航角
         */
        @JsonProperty(value = "waypointHeadingPathMode")
        public String waypointHeadingPathMode = "followBadArc";


    }

    @Data
    static class WaypointTurnParam {
        /**
         * coordinateTurn：协调转弯，不过点，提前转弯
         * toPointAndStopWithDiscontinuityCurvature：直线飞行，飞行器到点停
         * toPointAndStopWithContinuityCurvature：曲线飞行，飞行器到点停
         * toPointAndPassWithContinuityCurvature：曲线飞行，飞行器过点不停
         */
        @JsonProperty(value = "waypointTurnMode")
        public String waypointTurnMode = "toPointAndStopWithDiscontinuityCurvature";

        /**
         * 航点转弯截距
         */
        @JsonProperty(value = "waypointTurnDampingDist")
        public String waypointTurnDampingDist = "0.2";

    }

    @Data
    static class ActionGroup implements Serializable {

        private static final long serialVersionUID = 283090041195940467L;
        /**
         * 动作组id
         * * 注：在一个kmz文件内该ID唯一。建议从0开始单调连续递增。
         */
        @IncreaseId
        public String actionGroupId;


        /**
         * 动作组开始生效的航点
         */
        @JsonProperty(value = "actionGroupStartIndex")
        public String actionGroupStartIndex = "0";

        /**
         * 动作组结束生效的航点
         */
        @JsonProperty(value = "actionGroupEndIndex")
        public String actionGroupEndIndex = "0";

        /**
         * 动作执行模式
         */
        @JsonProperty(value = "actionGroupMode")
        public String actionGroupMode = "sequence";

        /**
         * 动作触发器类型
         */
        @JsonProperty(value = "actionTrigger")
        public ActionTrigger actionTrigger;

        /**
         * 动作
         */
        @JsonProperty(value = "action")
        public List<Action> action;

        @Data
        static class ActionTrigger {
            /**
             * 动作触发器类型
             * reachPoint：到达航点时执行
             * betweenAdjacentPoints：航段触发，均匀转云台
             * multipleTiming：等时触发
             * multipleDistance：等距触发
             * * 注：“betweenAdjacentPoints”需配合动作"gimbalEvenlyRotate"使用*
             */
            @JsonProperty(value = "actionTriggerType")
            public String actionTriggerType;

            /**
             * 动作触发器参数
             * > 0
             * * 注：当“actionTriggerType”为“multipleTiming”时，该元素表示间隔时间，单位是s；当“actionTriggerType”为“multipleDistance”时，该元素表示间隔距离，单位是m。*
             */
            @JsonProperty(value = "actionTriggerParam")
            public String actionTriggerParam;
        }

        @Data
        static class Action {
            /**
             * 动作id
             * 注：在一个动作组内该ID唯一。建议从0开始单调连续递增。
             */
            @IncreaseId
            public String actionId;

            /**
             * 动作类型 takePhoto：单拍
             * startRecord：开始录像
             * stopRecord：结束录像
             * focus：对焦
             * zoom：变焦
             * customDirName：创建新文件夹
             * gimbalRotate：旋转云台
             * rotateYaw：飞行器偏航
             * hover：悬停等待
             */
            @JsonProperty(value = "actionActuatorFunc")
            public String actionActuatorFunc;

            /**
             * 动作参数
             */
            @JsonProperty(value = "actionActuatorFuncParam")
            public ActionActuatorFuncParam actionActuatorFuncParam = new ActionActuatorFuncParam();

            @Data
            static class ActionActuatorFuncParam {
                /**
                 * 负载挂载位置
                 */
                @JsonProperty(value = "payloadPositionIndex")
                @ActionParam(value = {"all"})
                public String payloadPositionIndex = "0";

                /**
                 * 拍摄照片文件后缀
                 */
                @JsonProperty(value = "fileSuffix")
                @ActionParam(value = {"startRecord","takePhoto"})
                public String fileSuffix;

                /**
                 * 拍摄照片存储类型
                 * zoom: 存储变焦镜头拍摄照片
                 * wide: 存储广角镜头拍摄照片
                 * ir: 存储红外镜头拍摄照片
                 * narrow_band: 存储窄带镜头拍摄照片
                 * 注：存储多个镜头照片，格式如“<wpml:payloadLensIndex>wide,ir,narrow_band</wpml:payloadLensIndex>”表示同时使用广角、红外和窄带镜头
                 */
                @JsonProperty(value = "payloadLensIndex")
                @ActionParam(value = {"startRecord","takePhoto","stopRecord"})
                public String payloadLensIndex;

                /**
                 * 是否使用全局存储类型 0：不使用全局设置
                 * 1：使用全局设置
                 */
                @JsonProperty(value = "useGlobalPayloadLensIndex")
                @ActionParam(value = {"startRecord","takePhoto"})
                public String useGlobalPayloadLensIndex="0";

                /**
                 * 是否点对焦 0：区域对焦 1：点对焦
                 */
                @JsonProperty(value = "isPointFocus")
                @ActionParam(value = {"focus"})
                public String isPointFocus="1";


                @JsonProperty(value = "isUseFocalFactor")
                @ActionParam(value = {"zoom"})
                public String isUseFocalFactor="0";
                /**
                 * 对焦点位置
                 */
                @JsonProperty(value = "focusY")
                @ActionParam(value = {"focus"})
                public String focusY;

                /**
                 * 对焦点位置
                 */
                @JsonProperty(value = "focusX")
                @ActionParam(value = {"focus"})
                public String focusX;

                /**
                 * 对焦区域宽度比
                 */
                @JsonProperty(value = "focusRegionWidth")
                @ActionParam(value = {"focus"})
                public String focusRegionWidth;

                /**
                 * 对焦区域高度比
                 */
                @JsonProperty(value = "focusRegionHeight")
                @ActionParam(value = {"focus"})
                public String focusRegionHeight;

                /**
                 * 是否无穷远对焦 0: 非无穷远对焦 1: 无穷远对焦
                 */
                @JsonProperty(value = "isInfiniteFocus")
                @ActionParam(value = {"focus"})
                public String isInfiniteFocus;

                /**
                 * 变焦焦距
                 */
                @JsonProperty(value = "focalLength")
                @ActionParam(value = {"zoom"})
                public String focalLength;

                /**
                 * 新文件夹的名称
                 */
                @JsonProperty(value = "directoryName")
                @ActionParam(value = {"customDirName"})
                public String directoryName;

                /**
                 * 云台偏航角转动坐标系
                 */
                @JsonProperty(value = "gimbalHeadingYawBase")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalHeadingYawBase = "north";

                /**
                 * 云台转动模式
                 * relativeAngle：相对角度
                 * absoluteAngle：绝对角度
                 */
                @JsonProperty(value = "gimbalRotateMode")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalRotateMode = "absoluteAngle";

                /**
                 * 是否使能云台Pitch转动
                 * 0：不使能
                 * 1：使能
                 */
                @JsonProperty(value = "gimbalPitchRotateEnable")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalPitchRotateEnable = "0";

                /**
                 * 云台Pitch转动角度
                 */
                @JsonProperty(value = "gimbalPitchRotateAngle")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalPitchRotateAngle = "0";

                /**
                 * 是否使能云台Roll转动 0：不使能
                 * 1：使能
                 */
                @JsonProperty(value = "gimbalRollRotateEnable")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalRollRotateEnable = "0";


                /**
                 * 云台Roll转动角度
                 */
                @JsonProperty(value = "gimbalRollRotateAngle")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalRollRotateAngle = "0";

                /**
                 * 是否使能云台Yaw转动
                 * 0：不使能
                 * 1：使能
                 */
                @JsonProperty(value = "gimbalYawRotateEnable")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalYawRotateEnable = "1";

                /**
                 * 云台Yaw转动角度
                 */
                @JsonProperty(value = "gimbalYawRotateAngle")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalYawRotateAngle="";

                /**
                 * 是否使能云台转动时间
                 * 0：不使能
                 * 1：使能
                 */
                @JsonProperty(value = "gimbalRotateTimeEnable")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalRotateTimeEnable = "0";

                /**
                 * 云台完成转动用时
                 */
                @JsonProperty(value = "gimbalRotateTime")
                @ActionParam(value = {"gimbalRotate"})
                public String gimbalRotateTime = "0";

                /**
                 * 飞行器目标偏航角（相对于地理北）
                 */
                @JsonProperty(value = "aircraftHeading")
                @ActionParam(value = {"rotateYaw"})
                public String aircraftHeading;

                /**
                 * 飞行器偏航角转动模式
                 * clockwise：顺时针旋转
                 * counterClockwise：逆时针旋转*
                 */
                @JsonProperty(value = "aircraftPathMode")
                @ActionParam(value = {"rotateYaw"})
                public String aircraftPathMode = "clockwise";

                /**
                 * 飞行器悬停等待时间
                 */
                @JsonProperty(value = "hoverTime")
                @ActionParam(value = {"hover"})
                public String hoverTime;

            }
        }
    }


    public static void analysisPoint(TravelRecordRequest travelRecordRequest, Element placeMarkElement) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // waypointHeadingParam 解析
        WaypointHeadingParam waypointHeadingParam = travelRecordRequest.getWaypointHeadingParam();
        for (Field declaredField : waypointHeadingParam.getClass().getDeclaredFields()) {
            placeMarkElement.addElement("wpml:" + declaredField.getName()).addText(String.valueOf(waypointHeadingParam.getClass().getMethod("get" + firstUpperCase(declaredField.getName())).invoke(waypointHeadingParam)));
        }
        //waypointTurnParam 解析
        WaypointTurnParam waypointTurnParam = travelRecordRequest.getWaypointTurnParam();
        for (Field declaredField : waypointTurnParam.getClass().getDeclaredFields()) {
            placeMarkElement.addElement("wpml:" + declaredField.getName()).addText(String.valueOf(waypointTurnParam.getClass().getMethod("get" + firstUpperCase(declaredField.getName())).invoke(waypointTurnParam)));
        }
        //actionGroup 解析
        if (travelRecordRequest.actionGroup == null) {
            return;
        }
        Element actionGroupElement = placeMarkElement.addElement("wpml:actionGroup");
        ActionGroup actionGroup = travelRecordRequest.actionGroup;
        int i = 0;
        String val = "";
        for (Field declaredField : actionGroup.getClass().getDeclaredFields()) {
            if (declaredField.getType().getName().equals(String.class.getName())) {
                IncreaseId increaseId = declaredField.getAnnotation(IncreaseId.class);
                if (increaseId != null) {
                    i++;
                    actionGroupElement.addElement("wpml:" + declaredField.getName()).addText(String.valueOf(i));
                } else {
                    val = getValue(actionGroup.getClass().getMethod("get" + firstUpperCase(declaredField.getName())), actionGroup);
                    if (StringUtils.hasText(val)) {
                        actionGroupElement.addElement("wpml:" + declaredField.getName()).addText(val);
                    }
                }
            }
            //是属性类
            if (declaredField.getType().getPackageName().startsWith(TravelRecordRequest.class.getPackageName())) {
                Element actionTrigger = actionGroupElement.addElement("wpml:" + declaredField.getName());
                if (declaredField.getType().getName().endsWith(ACTION_TRIGGER_NAME)) {
                    for (Field field : declaredField.getType().getDeclaredFields()) {
                        val = getValue(field.getDeclaringClass().getMethod("get" + firstUpperCase(field.getName())), travelRecordRequest.actionGroup.getActionTrigger());
                        if (StringUtils.hasText(val)) {
                            actionTrigger.addElement("wpml:" + field.getName()).addText(val);
                        }
                    }
                }
            }
        }
        if (actionGroup.getAction() == null) {
            return;
        }
        boolean hasGimbalRotate = false;
        for (ActionGroup.Action action : actionGroup.getAction()) {
            //云台操作最后要回中
            if("gimbalRotate".equals(action.actionActuatorFunc)){
                hasGimbalRotate = true;
            }
            i++;
            Element elementAction = actionGroupElement.addElement("wpml:action");
            elementAction.addElement("wpml:actionId").addText(String.valueOf(i));
            if (StringUtils.hasText(action.getActionActuatorFunc())) {
                elementAction.addElement("wpml:actionActuatorFunc").addText(action.getActionActuatorFunc());
            }
            ActionGroup.Action.ActionActuatorFuncParam param = action.getActionActuatorFuncParam();
            if (param == null) {
                return;
            }
            String act = action.getActionActuatorFunc();
            Element elementActionActuatorFuncParam = elementAction.addElement("wpml:actionActuatorFuncParam");
            for (Field declaredField : param.getClass().getDeclaredFields()) {
                //获取注解判断是否需要添加
                ActionParam annotation = declaredField.getAnnotation(ActionParam.class);
                if(annotation!=null){
                    String[] v =annotation.value();
                    if(!Arrays.asList(v).contains(act)){
                        continue;
                    }
                }
                val = getValue(declaredField.getDeclaringClass().getMethod("get" + firstUpperCase(declaredField.getName())),param);
                if(StringUtils.hasText(val)){
                    elementActionActuatorFuncParam.addElement("wpml:" + declaredField.getName()).addText(val);
                }
            }
        }
        //云台回中
        if(hasGimbalRotate){
            i++;
            Element elementAction = actionGroupElement.addElement("wpml:action");
            elementAction.addElement("wpml:actionId").addText(String.valueOf(i));
            elementAction.addElement("wpml:actionActuatorFunc").addText("gimbalRotate");
            Element elementActionActuatorFuncParam = elementAction.addElement("wpml:actionActuatorFuncParam");
            elementActionActuatorFuncParam.addElement("wpml:gimbalHeadingYawBase").addText("aircraft");
            elementActionActuatorFuncParam.addElement("wpml:gimbalRotateMode").addText("absoluteAngle");
            elementActionActuatorFuncParam.addElement("wpml:gimbalPitchRotateEnable").addText("1");
            elementActionActuatorFuncParam.addElement("wpml:gimbalPitchRotateAngle").addText("0");
            elementActionActuatorFuncParam.addElement("wpml:gimbalRollRotateEnable").addText("0");
            elementActionActuatorFuncParam.addElement("wpml:gimbalRollRotateAngle").addText("0");
            elementActionActuatorFuncParam.addElement("wpml:gimbalYawRotateEnable").addText("0");
            elementActionActuatorFuncParam.addElement("wpml:gimbalYawRotateAngle").addText("0");
            elementActionActuatorFuncParam.addElement("wpml:gimbalRotateTimeEnable").addText("0");
            elementActionActuatorFuncParam.addElement("wpml:gimbalRotateTime").addText("10");
            elementActionActuatorFuncParam.addElement("wpml:payloadPositionIndex").addText("0");
        }

    }

    public static String firstUpperCase(String str) {
        return str.replaceFirst(str.substring(0, 1), str.substring(0, 1).toUpperCase());
    }

    public static String getValue(Method method, Object object) {
        try {
            Object o = method.invoke(object);
            if (Objects.isNull(o)) {
                return "";
            }
            return String.valueOf(o);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return "";
    }

}
